﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.Web;
using System.Globalization;
using System.IO;

namespace Succell.Dnn.JQuery.UI
{
    /// <summary>
    /// A helper class for ensuring the JQuery UI infrastructure.
    /// </summary>
    public static class JQueryUI
    {
        #region constants

        private const string JQueryUIVersion = "1.7.2";
        private static readonly string RegisteredThemesKey = typeof (JQueryUI).FullName + "$RegisteredThemes";
        private static readonly string DefaultThemeKey = typeof (JQueryUI).FullName + "$DefaultTheme";
        private static readonly string RegisteredLocalesKey = typeof (JQueryUI).FullName + "$RegisteredLocales";
        private static readonly string AllLocalesRegisteredKey = typeof (JQueryUI).FullName + "$AllLocalesRegistered";
        private const string GlobalLocaleUrl = "~/DesktopModules/Succell.JQuery/js/i18n/jquery-ui-i18n.min.js";
        private const string WidgetLocaleUrlFormat = "~/DesktopModules/Succell.JQuery/js/i18n/ui.{0}-{1}.min.js";

        #endregion

        #region extension methods

        /// <summary>
        /// Registers jQuery UI for the given page.
        /// </summary>
        /// <param name="page">The page for which to register jQuery UI.</param>
        public static void RegisterJQueryUI(this Page page)
        {
            if (null == page)
                throw new ArgumentNullException("page");

            page.RegisterJQuery();
            page.ClientScript.RegisterClientScriptInclude(typeof(JQueryUI), "jquery-ui-" + JQueryUIVersion, VirtualPathUtility.ToAbsolute("~/DesktopModules/Succell.JQuery/js/jquery-ui-" + JQueryUIVersion + ".min.js"));
            page.RegisterJQueryUITheme("smoothness", "~/DesktopModules/Succell.JQuery/css/smoothness/");
        }

        private static List<string> GetRegisteredThemes(this Page page)
        {
            List<string> registeredThemes = page.Items[RegisteredThemesKey] as List<string>;
            if (null == registeredThemes)
            {
                registeredThemes = new List<string>();
                page.Items[RegisteredThemesKey] = registeredThemes;
            }
            return registeredThemes;
        }

        /// <summary>
        /// Gets whether a specific theme has been registered for the given page.
        /// </summary>
        /// <param name="page">The page to check.</param>
        /// <param name="themeName">The theme to check for.</param>
        /// <returns><c>true</c> if the theme has been registered on the page, otherwise
        /// <c>false</c>.</returns>
        public static bool IsJQueryUIThemeRegistered(this Page page, string themeName)
        {
            return page.GetRegisteredThemes().Contains(themeName.ToLowerInvariant());
        }

        /// <summary>
        /// Registers a jQuery UI theme on a page.
        /// </summary>
        /// <param name="page">The page to register the theme on.</param>
        /// <param name="themeName">The name of the theme to register.</param>
        public static void RegisterJQueryUITheme(this Page page, string themeName)
        {
            if (null == page)
                throw new ArgumentNullException("page");

            page.RegisterJQueryUITheme(themeName, null);
        }

        /// <summary>
        /// Registers a jQuery UI theme on a page.
        /// </summary>
        /// <param name="page">The page to register the theme on.</param>
        /// <param name="themeName">The name of the theme to register.</param>
        /// <param name="themePath">The path to the theme's stylesheet.</param>
        public static void RegisterJQueryUITheme(this Page page, string themeName, string themePath)
        {
            page.RegisterJQueryUITheme(themeName, themePath, JQueryUIVersion);
        }

        /// <summary>
        /// Registers a jQuery UI theme on a page.
        /// </summary>
        /// <param name="page">The page to register the theme on.</param>
        /// <param name="themeName">The name of the theme to register.</param>
        /// <param name="themePath">The path to the theme's stylesheet.</param>
        /// <param name="version">The version of jQuery UI.</param>
        public static void RegisterJQueryUITheme(this Page page, string themeName, string themePath, string version)
        {
            if (null == page)
                throw new ArgumentNullException("page");

            themeName = themeName.ToLowerInvariant();
            if (String.IsNullOrEmpty(themePath))
            {
                StringBuilder themeNameUcFirst = new StringBuilder(themeName);
                themeNameUcFirst[0] = Char.ToUpperInvariant(themeNameUcFirst[0]);
                themePath = "~/DesktopModules/Succell.JQuery." + themeNameUcFirst + "/";
            }
            List<string> registeredThemes = page.GetRegisteredThemes();
            if (!registeredThemes.Contains(themeName))
            {
                string stylesheetUrl = VirtualPathUtility.Combine(
                    themePath,
                    String.Format(CultureInfo.InvariantCulture,
                                  "jquery-ui-{0}.{1}.css", version, themeName));

                if (!File.Exists(page.Server.MapPath(stylesheetUrl)))
                    throw new ArgumentException("The theme does not exist on the server.", "themeName");

                registeredThemes.Add(themeName);
                page.AddStylesheet(stylesheetUrl);
                if (String.IsNullOrEmpty(page.GetDefaultJQueryUITheme()))
                {
                    page.SetDefaultJQueryUITheme(themeName);
                }
            }
        }

        /// <summary>
        /// Gets the default jQuery UI theme for the page.
        /// </summary>
        /// <param name="page">The page for which to get the default theme.</param>
        /// <returns>The name of the default jQuery UI theme for the page.</returns>
        public static string GetDefaultJQueryUITheme(this Page page)
        {
            if (null == page)
                throw new ArgumentNullException("page");

            return page.Items[DefaultThemeKey] as string;
        }

        /// <summary>
        /// Sets the default jQuery UI theme for the page.
        /// </summary>
        /// <param name="page">The page for which to set the default theme.</param>
        /// <param name="themeName">The name of the default jQuery UI theme for the page.</param>
        public static void SetDefaultJQueryUITheme(this Page page, string themeName)
        {
            if (null == page)
                throw new ArgumentNullException("page");
            if (String.IsNullOrEmpty(themeName))
                throw new ArgumentNullException("themeName");

            themeName = themeName.ToLowerInvariant();
            if (!page.GetRegisteredThemes().Contains(themeName))
                throw new ArgumentException("The given theme has not been registered.", "themeName");

            page.Items[DefaultThemeKey] = themeName;
        }

        private static List<string> GetRegisteredJQueryUILocales(this Page page)
        {
            List<string> registeredLocales = page.Items[RegisteredLocalesKey] as List<string>;
            if (null == registeredLocales)
            {
                registeredLocales = new List<string>();
                page.Items[RegisteredLocalesKey] = registeredLocales;
            }
            return registeredLocales;
        }

        /// <summary>
        /// Registers a jQuery UI locale for a widget on a page.
        /// </summary>
        /// <param name="page">The page on which to register the locale.</param>
        /// <param name="widget">The widget type to register the locale for.</param>
        /// <param name="locale">The locale to register.</param>
        public static void RegisterJQueryUILocale(this Page page, string widget, string locale)
        {
            if (null == page)
                throw new ArgumentNullException("page");
            if (String.IsNullOrEmpty(widget))
                throw new ArgumentNullException("widget");
            if (String.IsNullOrEmpty(locale))
                throw new ArgumentNullException("locale");

            string localePath = VirtualPathUtility.ToAbsolute(String.Format(CultureInfo.InvariantCulture, WidgetLocaleUrlFormat, widget, locale));
            if (!File.Exists(page.Server.MapPath(localePath)))
                throw new ArgumentException("The specified locale does not exist for the widget.");

            List<string> registeredLocales = page.GetRegisteredJQueryUILocales();
            if (!registeredLocales.Contains(localePath))
            {
                registeredLocales.Add(localePath);
                page.PreRenderComplete += page_PreRenderComplete;
            }
        }

        /// <summary>
        /// Registers all locales on a page.
        /// </summary>
        /// <param name="page">The page on which to register all locales.</param>
        public static void RegisterAllJQueryUILocales(this Page page)
        {
            if (null == page)
                throw new ArgumentNullException("page");

            page.ClientScript.RegisterClientScriptInclude(typeof(JQueryUI), "AllLocales", VirtualPathUtility.ToAbsolute(GlobalLocaleUrl));
            page.Items[AllLocalesRegisteredKey] = true;
        }

        private static bool AreAllJQueryUILocalesRegistered(this Page page)
        {
            return null != page.Items[AllLocalesRegisteredKey];
        }

        #endregion

        #region static event handlers

        private static void page_PreRenderComplete(object sender, EventArgs e)
        {
            Page page = (Page)sender;
            List<string> locales = page.GetRegisteredJQueryUILocales();
            if (locales.Count > 0 && !page.AreAllJQueryUILocalesRegistered())
            {
                if (locales.Count > 10)
                {
                    page.RegisterAllJQueryUILocales();
                }
                else
                {
                    foreach (string localeUrl in locales)
                    {
                        page.ClientScript.RegisterClientScriptInclude(typeof(JQueryUI), localeUrl, localeUrl);
                    }
                }
            }
        }

        #endregion
    }
}
